LCOV - code coverage report
Current view: top level - src - scram.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 58 0
Test Date: 2024-06-28 00:00:00 Functions: 0.0 % 5 0

            Line data    Source code
       1              : /* SPDX-License-Identifier: MIT OR GPL-3.0-only */
       2              : /* scram.c
       3              :  * strophe XMPP client library
       4              :  *
       5              :  * SCRAM-SHA1 helper functions according to RFC5802
       6              :  * HMAC-SHA1 implementation according to RFC2104
       7              :  *
       8              :  * Copyright (C) 2013 Dmitry Podgorny <pasis.ua@gmail.com>
       9              :  *
      10              :  *  This software is provided AS-IS with no warranty, either express
      11              :  *  or implied.
      12              :  *
      13              :  *  This program is dual licensed under the MIT or GPLv3 licenses.
      14              :  */
      15              : 
      16              : /** @file
      17              :  *  SCRAM-SHA1 helper functions.
      18              :  */
      19              : 
      20              : #include <assert.h>
      21              : #include <string.h>
      22              : 
      23              : #include "common.h"
      24              : #include "sha1.h"
      25              : #include "sha256.h"
      26              : #include "sha512.h"
      27              : #include "ostypes.h"
      28              : 
      29              : #include "scram.h"
      30              : 
      31              : #define HMAC_BLOCK_SIZE_MAX 128
      32              : 
      33              : static const uint8_t ipad = 0x36;
      34              : static const uint8_t opad = 0x5C;
      35              : 
      36              : const struct hash_alg scram_sha1 = {
      37              :     "SCRAM-SHA-1",
      38              :     SASL_MASK_SCRAMSHA1,
      39              :     SHA1_DIGEST_SIZE,
      40              :     (void (*)(const uint8_t *, size_t, uint8_t *))crypto_SHA1,
      41              :     (void (*)(void *))crypto_SHA1_Init,
      42              :     (void (*)(void *, const uint8_t *, size_t))crypto_SHA1_Update,
      43              :     (void (*)(void *, uint8_t *))crypto_SHA1_Final};
      44              : 
      45              : const struct hash_alg scram_sha1_plus = {
      46              :     "SCRAM-SHA-1-PLUS",
      47              :     SASL_MASK_SCRAMSHA1_PLUS,
      48              :     SHA1_DIGEST_SIZE,
      49              :     (void (*)(const uint8_t *, size_t, uint8_t *))crypto_SHA1,
      50              :     (void (*)(void *))crypto_SHA1_Init,
      51              :     (void (*)(void *, const uint8_t *, size_t))crypto_SHA1_Update,
      52              :     (void (*)(void *, uint8_t *))crypto_SHA1_Final};
      53              : 
      54              : const struct hash_alg scram_sha256 = {
      55              :     "SCRAM-SHA-256",
      56              :     SASL_MASK_SCRAMSHA256,
      57              :     SHA256_DIGEST_SIZE,
      58              :     (void (*)(const uint8_t *, size_t, uint8_t *))sha256_hash,
      59              :     (void (*)(void *))sha256_init,
      60              :     (void (*)(void *, const uint8_t *, size_t))sha256_process,
      61              :     (void (*)(void *, uint8_t *))sha256_done};
      62              : 
      63              : const struct hash_alg scram_sha256_plus = {
      64              :     "SCRAM-SHA-256-PLUS",
      65              :     SASL_MASK_SCRAMSHA256_PLUS,
      66              :     SHA256_DIGEST_SIZE,
      67              :     (void (*)(const uint8_t *, size_t, uint8_t *))sha256_hash,
      68              :     (void (*)(void *))sha256_init,
      69              :     (void (*)(void *, const uint8_t *, size_t))sha256_process,
      70              :     (void (*)(void *, uint8_t *))sha256_done};
      71              : 
      72              : const struct hash_alg scram_sha512 = {
      73              :     "SCRAM-SHA-512",
      74              :     SASL_MASK_SCRAMSHA512,
      75              :     SHA512_DIGEST_SIZE,
      76              :     (void (*)(const uint8_t *, size_t, uint8_t *))sha512_hash,
      77              :     (void (*)(void *))sha512_init,
      78              :     (void (*)(void *, const uint8_t *, size_t))sha512_process,
      79              :     (void (*)(void *, uint8_t *))sha512_done};
      80              : 
      81              : const struct hash_alg scram_sha512_plus = {
      82              :     "SCRAM-SHA-512-PLUS",
      83              :     SASL_MASK_SCRAMSHA512_PLUS,
      84              :     SHA512_DIGEST_SIZE,
      85              :     (void (*)(const uint8_t *, size_t, uint8_t *))sha512_hash,
      86              :     (void (*)(void *))sha512_init,
      87              :     (void (*)(void *, const uint8_t *, size_t))sha512_process,
      88              :     (void (*)(void *, uint8_t *))sha512_done};
      89              : 
      90              : /* The order of this list defines the order in which the SCRAM algorithms are
      91              :  * tried if the server supports them.
      92              :  * Their order is derived from
      93              :  * https://datatracker.ietf.org/doc/html/draft-ietf-kitten-password-storage
      94              :  */
      95              : const struct hash_alg *scram_algs[] = {
      96              :     /* *1 */
      97              :     &scram_sha512_plus,
      98              :     /* *1 */
      99              :     &scram_sha256_plus,
     100              :     /* *1 */
     101              :     &scram_sha1_plus,
     102              :     /* *1 */
     103              :     &scram_sha512,
     104              :     /* *1 */
     105              :     &scram_sha256,
     106              :     /* *1 */
     107              :     &scram_sha1,
     108              : };
     109              : /* *1 - I want to use clang-format here, but by default it will put multiple
     110              :  * elements per line if there's no comment. Currently clang-format also doesn't
     111              :  * have an option to enforce it to behave like that, besides by putting comments
     112              :  * between each element (or I couldn't find a way to do it). In order to prevent
     113              :  * clang-format from re-formatting the array I added the comments above and
     114              :  * wrote this lengthy description.
     115              :  */
     116              : const size_t scram_algs_num = sizeof(scram_algs) / sizeof(scram_algs[0]);
     117              : 
     118              : union common_hash_ctx {
     119              :     SHA1_CTX sha1;
     120              :     sha256_context sha256;
     121              :     sha512_context sha512;
     122              : };
     123              : 
     124            0 : static void crypto_HMAC(const struct hash_alg *alg,
     125              :                         const uint8_t *key,
     126              :                         size_t key_len,
     127              :                         const uint8_t *text,
     128              :                         size_t len,
     129              :                         uint8_t *digest)
     130              : {
     131            0 :     uint8_t key_pad[HMAC_BLOCK_SIZE_MAX];
     132            0 :     uint8_t key_ipad[HMAC_BLOCK_SIZE_MAX];
     133            0 :     uint8_t key_opad[HMAC_BLOCK_SIZE_MAX];
     134            0 :     uint8_t sha_digest[SCRAM_DIGEST_SIZE];
     135            0 :     size_t blocksize;
     136            0 :     size_t i;
     137            0 :     union common_hash_ctx ctx;
     138              : 
     139            0 :     assert(alg->digest_size <= HMAC_BLOCK_SIZE_MAX);
     140            0 :     blocksize = alg->digest_size < 48 ? 64 : 128;
     141              : 
     142            0 :     memset(key_pad, 0, blocksize);
     143            0 :     if (key_len <= blocksize) {
     144            0 :         memcpy(key_pad, key, key_len);
     145              :     } else {
     146              :         /* according to RFC2104 */
     147            0 :         alg->hash(key, key_len, key_pad);
     148              :     }
     149              : 
     150            0 :     for (i = 0; i < blocksize; i++) {
     151            0 :         key_ipad[i] = key_pad[i] ^ ipad;
     152            0 :         key_opad[i] = key_pad[i] ^ opad;
     153              :     }
     154              : 
     155            0 :     alg->init((void *)&ctx);
     156            0 :     alg->update((void *)&ctx, key_ipad, blocksize);
     157            0 :     alg->update((void *)&ctx, text, len);
     158            0 :     alg->final((void *)&ctx, sha_digest);
     159              : 
     160            0 :     alg->init((void *)&ctx);
     161            0 :     alg->update((void *)&ctx, key_opad, blocksize);
     162            0 :     alg->update((void *)&ctx, sha_digest, alg->digest_size);
     163            0 :     alg->final((void *)&ctx, digest);
     164            0 : }
     165              : 
     166            0 : static void SCRAM_Hi(const struct hash_alg *alg,
     167              :                      const uint8_t *text,
     168              :                      size_t len,
     169              :                      const uint8_t *salt,
     170              :                      size_t salt_len,
     171              :                      uint32_t i,
     172              :                      uint8_t *digest)
     173              : {
     174            0 :     size_t k;
     175            0 :     uint32_t j;
     176            0 :     uint8_t tmp[128];
     177              : 
     178            0 :     static uint8_t int1[] = {0x0, 0x0, 0x0, 0x1};
     179              : 
     180              :     /* assume salt + INT(1) isn't longer than sizeof(tmp) */
     181            0 :     assert(salt_len <= sizeof(tmp) - sizeof(int1));
     182              : 
     183            0 :     memset(digest, 0, alg->digest_size);
     184            0 :     if (i == 0) {
     185            0 :         return;
     186              :     }
     187              : 
     188            0 :     memcpy(tmp, salt, salt_len);
     189            0 :     memcpy(&tmp[salt_len], int1, sizeof(int1));
     190              : 
     191              :     /* 'text' for Hi is a 'key' for HMAC */
     192            0 :     crypto_HMAC(alg, text, len, tmp, salt_len + sizeof(int1), digest);
     193            0 :     memcpy(tmp, digest, alg->digest_size);
     194              : 
     195            0 :     for (j = 1; j < i; j++) {
     196            0 :         crypto_HMAC(alg, text, len, tmp, alg->digest_size, tmp);
     197            0 :         for (k = 0; k < alg->digest_size; k++) {
     198            0 :             digest[k] ^= tmp[k];
     199              :         }
     200              :     }
     201              : }
     202              : 
     203            0 : void SCRAM_ClientKey(const struct hash_alg *alg,
     204              :                      const uint8_t *password,
     205              :                      size_t len,
     206              :                      const uint8_t *salt,
     207              :                      size_t salt_len,
     208              :                      uint32_t i,
     209              :                      uint8_t *key)
     210              : {
     211            0 :     uint8_t salted[SCRAM_DIGEST_SIZE];
     212              : 
     213              :     /* XXX: Normalize(password) is omitted */
     214              : 
     215            0 :     SCRAM_Hi(alg, password, len, salt, salt_len, i, salted);
     216            0 :     crypto_HMAC(alg, salted, alg->digest_size, (uint8_t *)"Client Key",
     217              :                 strlen("Client Key"), key);
     218            0 : }
     219              : 
     220            0 : void SCRAM_ClientSignature(const struct hash_alg *alg,
     221              :                            const uint8_t *ClientKey,
     222              :                            const uint8_t *AuthMessage,
     223              :                            size_t len,
     224              :                            uint8_t *sign)
     225              : {
     226            0 :     uint8_t stored[SCRAM_DIGEST_SIZE];
     227              : 
     228            0 :     alg->hash(ClientKey, alg->digest_size, stored);
     229            0 :     crypto_HMAC(alg, stored, alg->digest_size, AuthMessage, len, sign);
     230            0 : }
     231              : 
     232            0 : void SCRAM_ClientProof(const struct hash_alg *alg,
     233              :                        const uint8_t *ClientKey,
     234              :                        const uint8_t *ClientSignature,
     235              :                        uint8_t *proof)
     236              : {
     237            0 :     size_t i;
     238            0 :     for (i = 0; i < alg->digest_size; i++) {
     239            0 :         proof[i] = ClientKey[i] ^ ClientSignature[i];
     240              :     }
     241            0 : }
        

Generated by: LCOV version 2.0-1